package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zmj.sy.mom.srv.aps.bean.entity.base.Message;
import com.zmj.sy.mom.srv.aps.bean.entity.base.UserMessage;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BasePageReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BasePageResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.SearchParam;
import com.zmj.sy.mom.srv.aps.bean.vo.usermessage.UserMessageGetResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.usermessage.UserMessageListResVo;
import com.zmj.sy.mom.srv.aps.mapper.MessageMapper;
import com.zmj.sy.mom.srv.aps.mapper.UserMessageMapper;
import com.zmj.sy.mom.srv.aps.utils.MkBeanUtils;
import com.zmj.sy.mom.srv.aps.utils.SySecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class UserMessageService {

    private final UserMessageMapper userMessageMapper;

    private final MessageMapper messageMapper;

    @Transactional
    public void add(Message reqVo) {
        messageMapper.insert(reqVo);
    }

    @Transactional(readOnly = true)
    public BasePageResVo<UserMessageListResVo> page(BasePageReqVo reqVo) {
        String userCode = SySecurityUtils.getUserCode();

        Map<String, String> params = new HashMap<>();
        params.put("userStatus", "um.status");
        List<SearchParam> userStatus = reqVo.getSearchParams().stream().filter(searchParam -> searchParam.getKey().equals("userStatus")).collect(Collectors.toList());
        reqVo.setSearchParams(reqVo.getSearchParams().stream().filter(searchParam -> !searchParam.getKey().equals("userStatus")).collect(Collectors.toList()));

        QueryWrapper<?> query = reqVo.query(params, "userStatus");

        String now = LocalDateTime.now().format(DatePattern.NORM_DATETIME_FORMATTER);
        query.ge("m.status", 2);
        query.and(qw1 -> {
            qw1.nested(qw2 ->
                        {
                            qw2.eq("m.scope", "global")
                                    .le("m.start_date_time", now)
                                    .ge("m.end_date_time", now);

                            if(CollUtil.isNotEmpty(userStatus) && userStatus.size() == 1 && userStatus.get(0).getType().equals("number:ne")){
                                qw2.and(qw3 -> qw3.ne("um.status", userStatus.get(0).getValue()).or().isNotNull("um.status"));
                            } else if (CollUtil.isNotEmpty(userStatus) && userStatus.size() == 1 && userStatus.get(0).getType().equals("number:eq")){
                                if(userStatus.get(0).getValue().equals("1")){
                                    qw2.and(qw3 -> qw3.eq("um.status", userStatus.get(0).getValue()).or().isNull("um.status"));
                                } else if (userStatus.get(0).getValue().equals("2")){
                                    qw2.and(qw3 -> qw3.eq("um.status", userStatus.get(0).getValue()));
                                }
                            }

                        }
            )
            .or()
            .nested(qw2 ->
                qw2.eq("m.scope", "personal")
//                        .and(qw3 -> qw3.ne("um.status", 2).or().isNotNull("um.status"))
                        .eq("m.user_code", userCode)
            );
        });

        Page<UserMessageListResVo> page = userMessageMapper.findByUserNotRead(query, reqVo.toPage());
        for (UserMessageListResVo record : page.getRecords()) {
            if(record.getStatus() == null){
                record.setStatus(1);
            }
        }

        return BasePageResVo.of(page, UserMessageListResVo.class);
    }

    @Transactional
    public void read(BaseIdReqVo reqVo) {
        String userCode = SySecurityUtils.getUserCode();

        UserMessage userMessage = userMessageMapper.lambdaQuery()
                .eq(UserMessage::getUserCode, userCode)
                .eq(UserMessage::getMessageId, reqVo.getId())
                .one();

        if(userMessage == null){
            userMessage = new UserMessage();
            userMessage.setStatus(2);
            userMessage.setMessageId(reqVo.getId());
            userMessage.setUserCode(userCode);
            userMessage.setReadTime(LocalDateTime.now());
            userMessageMapper.insert(userMessage);
            return ;
        }

        if(userMessage.getStatus().equals(2)){
            return ;
        }
        userMessage.setStatus(2);
        userMessageMapper.updateById(userMessage);
    }

    @SneakyThrows
    @Transactional
    public UserMessageGetResVo get(BaseIdReqVo reqVo) {
        Message message = messageMapper.selectById(reqVo.getId());
        read(reqVo);
        String s = FileUtils.readFileToString(new File(message.getContent()), "utf-8");
        message.setContent(s);
        return MkBeanUtils.copyProperties(message, UserMessageGetResVo.class);
    }

    @Transactional
    public void notRead(BaseIdReqVo reqVo) {
        String userCode = SySecurityUtils.getUserCode();

        UserMessage userMessage = userMessageMapper.lambdaQuery()
                .eq(UserMessage::getUserCode, userCode)
                .eq(UserMessage::getMessageId, reqVo.getId())
                .one();

        userMessage.setStatus(1);
        userMessageMapper.updateById(userMessage);
    }

    @Transactional
    public BasePageResVo<UserMessageListResVo> notReadList(BasePageReqVo reqVo) {
        String userCode = SySecurityUtils.getUserCode();

        Map<String, String> params = new HashMap<>();
        params.put("userStatus", "um.status");
        List<SearchParam> userStatus = reqVo.getSearchParams().stream().filter(searchParam -> searchParam.getKey().equals("userStatus")).collect(Collectors.toList());
        reqVo.setSearchParams(reqVo.getSearchParams().stream().filter(searchParam -> !searchParam.getKey().equals("userStatus")).collect(Collectors.toList()));

        QueryWrapper<?> query = reqVo.query(params, "userStatus");

        String now = LocalDateTime.now().format(DatePattern.NORM_DATETIME_FORMATTER);
        query.ge("m.status", 2);
        query.and(qw1 -> {
            qw1.nested(qw2 ->
                            {
                                qw2.eq("m.scope", "global")
                                        .le("m.start_date_time", now)
                                        .ge("m.end_date_time", now);

                                if(CollUtil.isNotEmpty(userStatus) && userStatus.size() == 1 && userStatus.get(0).getType().equals("number:ne")){
                                    qw2.and(qw3 -> qw3.ne("um.status", userStatus.get(0).getValue()).or().isNotNull("um.status"));
                                } else if (CollUtil.isNotEmpty(userStatus) && userStatus.size() == 1 && userStatus.get(0).getType().equals("number:eq")){
                                    if(userStatus.get(0).getValue().equals("1")){
                                        qw2.and(qw3 -> qw3.eq("um.status", userStatus.get(0).getValue()).or().isNull("um.status"));
                                    } else if (userStatus.get(0).getValue().equals("2")){
                                        qw2.and(qw3 -> qw3.eq("um.status", userStatus.get(0).getValue()));
                                    }
                                }

                            }
                    )
                    .or()
                    .nested(qw2 ->
                                    qw2.eq("m.scope", "personal")
//                        .and(qw3 -> qw3.ne("um.status", 2).or().isNotNull("um.status"))
                                            .eq("m.user_code", userCode)
                    );
        });

        Page<UserMessageListResVo> page = userMessageMapper.findByUserNotRead(query, reqVo.toPage());
        for (UserMessageListResVo record : page.getRecords()) {
            if(record.getStatus() == null){
                record.setStatus(1);
            }
        }

        return BasePageResVo.of(page, UserMessageListResVo.class);
    }
}
